﻿using System;
using System.Collections.Generic;
using System.Text;
using System.Threading;

namespace TCCHWLib.Commands
{
    public class BatchCommand : ICommand
    {
        private List<ICommand> m_CommandList = null;
        private PriorityKey m_Priority = null;
        private EventWaitHandle m_WaitHandler = null;

        public PriorityKey Priority
        {
            get { return m_Priority; }
            set { m_Priority = value; }
        }

        public ICommand this[int index]
        {
            get { return m_CommandList[index]; }
            //set { m_CommandList = value; }
        }
        public List<ICommand> CommandList
        {
            get { return m_CommandList; }
            set { m_CommandList = value; }
        }

        public BatchCommand()
        {
            m_CommandList = new List<ICommand>();
            m_WaitHandler = new AutoResetEvent(false);
        }

        public void AddCommand(ICommand cmd)
        {
            CommandList.Add(cmd);
        }

        public override object Execute(Processor processor)
        {
            ICommand cmd;
            object val = null;
            try
            {

                while (processor.PC != -1 && processor.PC < m_CommandList.Count)
                {
                    if (!Chip.Instance.IsManuallyControlled)
                        Thread.Sleep(500 + Chip.Instance.Random.Next(3) * 500);

                    // Fetch
                    cmd = m_CommandList[processor.PC];
                    //Function called before Executing the cmd
                    processor.Decode(cmd);
                    // Update UI
                    processor.UiProcessor.ProceedToCommand(processor.PC, cmd.ToString());
                    // Execute
                    //cmd.Value = val;
                    val = cmd.Execute(processor);
                    // Update UI
                    processor.UpdateListView();
                    processor.UiProcessor.ProceedToCommand(processor.PC, cmd.ToString());
                    // Set the PC to he next instruction
                    cmd.UpdatePC(processor);

                    Chip.Instance.SharedMemory.UpdateListView();

                    //if (!(cmd is TXCommitCommand))
                        processor.Cache.UpdateListView();

                    if (Chip.Instance.IsManuallyControlled && processor.PC != -1)
                        m_WaitHandler.WaitOne();
                }

            }
            catch (Exception ex)
            {
                return false;
            }
            return true;
        }

        public override void ExecuteGlobal(Processor processor)
        {
            foreach (ICommand cmd in m_CommandList)
            {
                processor.Decode(cmd);
                cmd.ExecuteGlobal(processor);
            }
            processor.Cache.Clear();
        }
    

        public override void Undo(Processor processor)
        {
            foreach (ICommand command in m_CommandList)
                command.Undo(processor);
        }

        internal void Proceed()
        {
            if (m_WaitHandler != null)
                m_WaitHandler.Set();
        }
    }
}
